using System.Net.Sockets;
using System.Net;

namespace Fusion.Net.UDP
{
    public enum UDPType
    { 
        Normal,
        Order,
        ReliableOrder
    }

    public class UDPClient : UDPNet
    {
        UDPType type;
        UDPSocket udpSocket;
        public UDPClient(int port, UDPType type = UDPType.Normal)
        {
            if (NetUtility.OSSupportsIPv6())
            {
                CreateSocket(port, AddressFamily.InterNetworkV6, type);
            }
            else if (NetUtility.OSSupportsIPv4())
            {
                CreateSocket(port, AddressFamily.InterNetwork, type);
            }
        }

        public UDPClient(int port, AddressFamily addressFamily, UDPType type = UDPType.Normal)
        {
            CreateSocket(port, addressFamily, type);
        }

        private void CreateSocket(int port, AddressFamily addressFamily, UDPType type = UDPType.Normal)
        {
            this.type = type;
            if (type == UDPType.Order)
            {
                socket = new OrderUDPClientSocket(this, addressFamily);
            }
            else if (type == UDPType.ReliableOrder)
            {
                socket = new ReliableOrderUDPClientSocket(this, addressFamily);
            }
            else
            {
                socket = new UDPClientSocket(this, addressFamily);
            }

            if (addressFamily == AddressFamily.InterNetworkV6)
            {
                socket.Bind(IPAddress.IPv6Any, port);
            }
            else if (addressFamily == AddressFamily.InterNetwork)
            {
                socket.Bind(IPAddress.Any, port);
            }

            udpSocket = socket as UDPSocket;
        }

        public void SetHeartBeats(float interval)
        {
            if (type == UDPType.ReliableOrder)
            {
                ReliableOrderUDPClientSocket roSocket = (ReliableOrderUDPClientSocket)socket;
                roSocket.SetHeartBeats(interval);
            }
        }

        public void SetHeartBeatsChecker(float interval)
        {
            if (type == UDPType.ReliableOrder)
            {
                ReliableOrderUDPClientSocket roSocket = (ReliableOrderUDPClientSocket)socket;
                roSocket.SetHeartBeatsChecker(interval);
            }
        }

        public void ClearCaches(string ip, int port)
        {
            if (socket == null)
            {
                return;
            }
            AddressFamily addressFamily = socket.Socket.AddressFamily;
            if (addressFamily == AddressFamily.InterNetwork)
            {
                string key = $"{ip}:{port}";
                udpSocket.ClearCaches(key);
            }
            else if (addressFamily == AddressFamily.InterNetworkV6)
            {
                string key = $"[{ip}]:{port}";
                udpSocket.ClearCaches(key);
            }
        }
    }
}


